package gender_normalizer;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;

import weka.core.Instances;
import weka.core.converters.ConverterUtils.DataSource;

public class Driver {

	/**
	 * @param args
	 * @throws Exception 
	 */
	static String dataSet = "DEVEL";
	static String dataLabel = "D1";
	static String before = "TRAIN";
	
	public static void main(String[] args) throws Exception {
		System.out.println("Reading in data...");
		long start = System.currentTimeMillis();
        DataSource source = new DataSource("C:/Users/Dan/Documents/My Dropbox/2011 Fall Class (Emotional Speech)/ALC/IS11."+dataSet+"_f.arff");
        Instances data = source.getDataSet();
        System.out.println("data read in " + (System.currentTimeMillis()-start)/1000 + " seconds");
       
        Scanner s = new Scanner(new File("C:/Users/Dan/Documents/My Dropbox/2011 Fall Class (Emotional Speech)/ALC/Subjects.txt"));
        HashMap<Integer, Subject> subjects = new HashMap<Integer, Subject>();
        while(s.hasNext()) {
        	String set = s.next();
        	System.out.println("'"+set+"'");
        	if(set.equals(dataLabel)) {
        		int id = s.nextInt();
        		char gender = s.next().charAt(0);
        		subjects.put(id, new Subject(gender));
        		s.nextLine();
        	}
        	else if(!set.equals(before))
        		break;
        	else
        		s.nextLine();
        }
        System.out.println(subjects.size() + " subjects added");
        
        DataSource ids = new DataSource("C:/Users/Dan/Documents/My Dropbox/2011 Fall Class (Emotional Speech)/ALC/BAC."+dataSet+".arff");
        Instances idEntries = ids.getDataSet();
        ArrayList<Integer> idList = new ArrayList<Integer>();
        for(int i=0; i < idEntries.numInstances(); i++) {
        	String name = idEntries.instance(i).stringValue(0);
        	int id = Integer.parseInt(name.split("_")[2]);
        	idList.add(id);
        }
        
        /*System.out.println("Begin user-normalizing");
        for(int i=0; i<data.numInstances(); i++) {
	        for(int j=0; j<data.numAttributes(); j++) {
	        	if(data.attribute(j).name().contains("F0")) {
	        		subjects.get(idList.get(i)).addValue(data.instance(i).value(j));
	        	}
	        }
        }
        for(int i=0; i<data.numInstances(); i++) {
	        for(int j=0; j<data.numAttributes(); j++) {
	        	if(data.attribute(j).name().contains("F0")) {
	        		Subject current = subjects.get(idList.get(i));
	        		double newValue = (data.instance(i).value(j) - current.getAverage()) / current.getStandardDeviation();
	        		data.instance(i).setValue(j, newValue);
	        	}
	        }
        }
        System.out.println("Finished user normalizing");*/
        
        System.out.println("Begin gender-normalizing");
        for(int i=0; i<data.numAttributes(); i++) {
        	if(data.attribute(i).name().contains("F0")) {
        		System.out.println("attribute to normalize:" + data.instance(0).attribute(i).name());
        		Subject male = new Subject('M');
        		Subject female = new Subject('F');
        		for(int j=0; j<data.numInstances(); j++) {
        			if(subjects.get(idList.get(j)).gender() == 'M') {
        				male.addValue(data.instance(j).value(i));
        			}
        			else {
        				female.addValue(data.instance(j).value(i));
        			}
        		}
        		
        		for(int j=0; j<data.numInstances(); j++) {
        			if(subjects.get(idList.get(j)).gender() == 'M') {
        				data.instance(j).setValue(i, computeZScore(data.instance(j).value(i), male.getAverage(), male.getStandardDeviation()));
        			}
        			else {
        				data.instance(j).setValue(i, computeZScore(data.instance(j).value(i), female.getAverage(), female.getStandardDeviation()));
        			}
        		}
        	}
        }
        System.out.println("Finished gender normalizing");
        
        System.out.println("Writing gender-normalized data set");
        BufferedWriter writer = new BufferedWriter( new FileWriter("C:/Users/Dan/Documents/My Dropbox/2011 Fall Class (Emotional Speech)/ALC/IS11."+dataSet+"_fg.arff"));
        writer.write(data.toString());
        writer.newLine();
        writer.flush();
        writer.close();
        System.out.println("Done writing");
	}
	
	static double computeZScore(double obs, double avg, double sd)
	{
		return (obs - avg) / sd;
	}
}

class Subject
{
	private char gender;
	private ArrayList<Double> values;
	
	public Subject(char gender)
	{
		this.gender = gender;
		values = new ArrayList<Double>();
	}
	
	public void addValue(double value)
	{
		values.add(value);
	}
	
	public double getAverage()
	{
		double sum = 0;
		for(int i=0; i < values.size(); i++)
			sum += values.get(i);
		return sum / (double)values.size();
	}
	
	public double getStandardDeviation()
	{
		double average = getAverage();
		double sum = 0;
		for(int i=0; i < values.size(); i++)
			sum += Math.pow(values.get(i) - average, 2);
		return Math.sqrt(sum / values.size());
	}
	
	public char gender()
	{
		return gender;
	}
}